//--------------------------------------------------
/**
 *
 *      Hand Gesture Recognition System
 *
 */
//--------------------------------------------------
/**
 * //TENFOLDINGMODELS CLASS//
 * Librería para el aprendizaje del sistema
 *
 * @author Edwin Cobos & Cesar Murcia
 * @version TenFoldingModels_v1.3
 *
 * Revisado: 01/12/11
 */
//--------------------------------------------------
//PACKAGE//
package HGR.Learning;

//IMPORT//
import hmm.ForwardBackward;
import hmm.Hmm;
import hmm.Model;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;


public class TenFoldingModels
{
    
    
    public static void main(String[] args)
    {
        //ArrayList<List> HistogramsFile = new ArrayList<List>();
        ArrayList[] HistogramsFiles = new ArrayList[10];
        for(int i=0; i<HistogramsFiles.length; i++)
            HistogramsFiles[i] = new ArrayList();

        String filename = "Histograms/";

   //     String Descriptors[] = {"SIFT", "SURF"};
        String Descriptors[] = {"SIFT"};
  //      int[] Angles = {10,15,30,45,60};
        int[] Angles = {15};
  //      int[] States = {2,3,4,5,6};
        int[] States = {5};

        int NumGestos = 8;
        int NumObsG = 39;

        float oldProbability = 0;
        float NewProbability = 1;
        boolean flag2 = false;
        boolean flag1 = false;        
        float[] D = new float[NumGestos];
        float min_D = Float.MAX_VALUE;

        // Leer histogramas        
        Punto test = null;
        float[][] MxConfusion = new float[NumGestos][NumGestos];

        int d,a,s,i,j,p,u,v,w;
        // Por cada tipo de descriptor
        for(d=0; d<Descriptors.length; d++)
        {
            // Por cada angulo
            for(a=0; a<Angles.length; a++)
            {
                // Por cada estado
                for(s=0; s<States.length; s++)
                {                    
                    Model[] l = new Model[NumGestos];
                    Punto[][] Observaciones = new Punto[NumGestos][NumObsG];

                  //  System.out.println("Cargando Archivos...");
                    for(u=0; u<Observaciones.length; u++)
                    {
                        for(v=0; v<Observaciones[u].length; v++)
                        {
                            Punto aaa = (Hmm.Iniciar(Angles[a], Descriptors[d], filename))[(Observaciones[u].length * u)+v];
                            Observaciones[u][v] = aaa;
                        }
                    }
                //    System.out.println("Cargando Archivos... ok");



                    flag1 = false;
                    for(i=0; i<10; i++)
                    {
                        oldProbability = 0;
                        NewProbability = 1;
                        //For convergencia minima de 2
                        for(j=0; j<2; j++)
                        {
                            for(u=0; u<Observaciones.length; u++)//8
                            {
                                min_D = Float.MAX_VALUE;
                                flag1 = false;
                                for(v=0; v<Observaciones[u].length; v++)
                                {
                                    if(!(v >= i*4 && v<(i*4)+4))
                                    {
                                        if(!flag1)
                                        {
                                            l[u] = Hmm.Hmm(Observaciones[u][v].MaxiHist, States[s], Angles[a]);
                                        }else{
                                            oldProbability = Hmm.CalcularProbabilidad(l[u], Observaciones[u][v].MaxiHist);
                                            l[u] = Hmm.Hmm_Learning(Observaciones[u][v].MaxiHist, l[u]);
                                            NewProbability = Hmm.CalcularProbabilidad(l[u], Observaciones[u][v].MaxiHist);

                                            if(Math.abs(NewProbability-oldProbability) < min_D)
                                            {
                                                min_D = Math.abs(NewProbability-oldProbability);
                                                D[u] = Math.abs(NewProbability-oldProbability);
                                            }                                            
                                        }
                                        if(flag1 == false)
                                        {
                                            flag1 = true;
                                        }                                        
                                    }
                                }
                            }
                        }//Fin For2
                        //System.out.println();
                        //System.out.print(l[0].toString());
                        //Model.writeModel(l[0], "lambda01.hmm");

                        // Convergencia Para cada Modelo (8)
                        /*for(u=0; u<Observaciones.length; u++)
                        {
                            flag1 = false;
                            flag2 = false;
                            oldProbability = 0;
                            NewProbability = 1;                            
                            //Do while Convergencia
                            do
                            {
                                //System.out.println("Iteracion "+u);
                                //Para todas las observaciones (39)
                                for(v=0; v<Observaciones[u].length; v++)
                                {
                                    if(!(v >= i*4 && v<(i*4)+4))
                                    {
                                        oldProbability = Hmm.CalcularProbabilidad(l[u], Observaciones[u][v].MaxiHist);
                                        if(!flag1)
                                        {
                                            l[u] = Hmm.Hmm(Observaciones[u][v].MaxiHist, States[s], Angles[a]);
                                        }else{
                                            l[u] = Hmm.Hmm_Learning(Observaciones[u][v].MaxiHist, l[u]);
                                        }

                                        if(flag1 == false)
                                        {
                                            flag1 = true;
                                        }

                                        NewProbability = Hmm.CalcularProbabilidad(l[u], Observaciones[u][v].MaxiHist);

                                        //System.out.println(Math.abs(NewProbability - oldProbability));
                                        if(Math.abs(NewProbability - oldProbability) <= D[u])
                                        {
                                            //System.out.println("v= "+v);
                                            flag2 = true;
                                            break;
                                        }                                        
                                    }//Fin if discriminación                                    
                                }// Fin obervaciones
                            }while(flag2 == false);                            
                        }//Fin Convergencia*/

                        for(u=0;u<l.length;u++)
                        {
                            Model.writeModel(l[u], "Modelos/lambda_0"+u+".hmm");
                        }
                        System.out.println("Modelos guardados");

                        

                        float[] pGest = new float[NumGestos];
                        //float minVal = Float.MAX_VALUE;
                        float minVal = Float.MIN_VALUE;
                        int minId = -1;
                        
                       for(u=0; u<Observaciones.length; u++)
                       {
                            for(v=0; v<Observaciones[u].length; v++)
                            {
                                //minVal = Float.MAX_VALUE;
                                minVal = Float.MIN_VALUE;
                                minId = -1;
                                if((v >= i*4 && v<(i*4)+4))
                                {
                                    //System.out.println("--------");
                                    for(w=0; w<Observaciones.length; w++)
                                    {
                                        pGest[w] = Hmm.CalcularProbabilidad(l[w], Observaciones[u][v].MaxiHist);
                                        //pGest[w] = (float)(Math.pow(10,Hmm.CalcularProbabilidad(l[w], Observaciones[u][v].MaxiHist)));
                                        //System.out.println(w + " " + pGest[w]);                                         
                                    }
                                   // System.out.println("--------");
                                    for(w=0; w<Observaciones.length; w++)
                                    {
                                        if(pGest[w] >  minVal)
                                        {
                                            minVal = pGest[w];
                                            minId = w;
                                        }
                                    }
                                    //System.out.println(minId);
                                    //Observaciones[u][v].m = minId;
                                    if(minId != -1)
                                    {
                                        Observaciones[u][v].m = minId;
                                        MxConfusion[u][minId]++;                                        
                                    }
                                }
                           }
                       }
                    }// Para todas las obs

                    System.out.println();
                    for(u=0; u<MxConfusion.length; u++)
                    {
                        for(v=0; v<MxConfusion[u].length; v++)
                        {
                            System.out.print(MxConfusion[u][v]+" ");
                        }
                        System.out.println();
                    }
                    System.out.println();
                    MxConfusion = new float[NumGestos][NumGestos];

                    System.out.println("State "+s );
                }// Fin cada estado
                System.out.println("Angle "+a);
            }//Fin cada angulo
            System.out.println("DESC "+d);
        }       

    }
    //--------------------------------------------------
    /**
     * Enlista los directorios y archivos de los videos
     * @param path Dirección de los archivos
     * @param dirs Lista donde se almacenan las direcciones
     * @param fileType Tipo de archivo que se enlista
     */
    public static void ListDir(String path, ArrayList<String> dirs, String fileType)
    {
        String t = path;
        File f = new File(t);
        if(f.isDirectory())
        {
            String[] fn = f.list();
            for(int i=0; i< fn.length; i++)
            {
                t = path+"/"+fn[i];
                ListDir(t, dirs,fileType);
            }
        }
        else if(f.isFile())
        {
            if(path.substring(path.length()-fileType.length(), path.length()).equals(fileType))
                dirs.add(path);
        }
    }

    public static void WriteObs(String Filename, int[][] t, int[][] f)
    {
        //Escribir los archivos de los histogramas

        //String[] parts = Filename.split("/");

        String filename = Filename+".txt";
        try
        {
            PrintWriter out = new PrintWriter(filename);


            out.println("MaxH \t IdG");
            for(int i=0;i<t.length; i++)
            {
                out.print(t[i][1]+" \t\t "+t[i][0]+"\n");
            }
            for(int i=0;i<f[0].length; i++)
            {
                out.print(f[1][i]+" \t\t "+f[0][i]+"\n");
                //out.print(f[i]+" ");
            }
            //out.print(value);

            out.close();
        }
        catch(FileNotFoundException e)
        {
            //IJ.error("SURF: savePointsToFile", e.getMessage());
        }
    }
    
  

    
    
}